<!--
=========================================================
* Argon Dashboard - v1.2.0
=========================================================
* Product Page: https://www.creative-tim.com/product/argon-dashboard


* Copyright  Creative Tim (http://www.creative-tim.com)
* Coded by www.creative-tim.com



=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head th:replace="fragments/common :: head_and_imports"></head>

<body>
<!-- Sidenav -->
<nav th:replace="fragments/common :: sidnav(3)"></nav>

<!-- Main content -->
<div class="main-content" id="panel">
	<!-- Topnav -->
	<nav class="navbar navbar-top navbar-expand navbar-dark bg-primary border-bottom d-md-none">
		<div class="container-fluid">
			<div class="collapse navbar-collapse row justify-content-between" id="navbarSupportedContent">
				<div class="row col-auto justify-content-end align-items-center m-0">
					<div class="col-auto">
						<ul class="navbar-nav align-items-center">
							<li class="nav-item d-xl-none">
								<!-- Sidenav toggler -->
								<div class="pr-2 sidenav-toggler sidenav-toggler-dark" data-action="sidenav-pin"
								     data-target="#sidenav-main">
									<div class="sidenav-toggler-inner">
										<i class="sidenav-toggler-line"></i>
										<i class="sidenav-toggler-line"></i>
										<i class="sidenav-toggler-line"></i>
									</div>
								</div>
							</li>
						</ul>
					</div>
				</div>
			</div>
		</div>
	</nav>
	
	<!-- Header -->
	<div class="header bg-primary">
		<div class="container-fluid">
			<!-- Header container -->
			<div class="container-fluid d-flex align-items-center">
				<div class="row">
					<div class="col-lg-10 col-md-10 mt-5 mb-8">
						<h1 class="display-2 text-white">Complexity Metrics</h1>
						<p class="text-white text-justify mb-3">
							This page is showing the metrics relevant to the coupling, including:
						</p>
						<p class="text-justify text-white mb-1 ml-4">
							<span class="text-bold">Afferent Coupling</span><span>, </span>
							If a class outside the package
							depends on a class in the package (incoming dependencies), it belongs to Afferent
							Coupling.
						</p>
						<p class="text-white text-justify mb-3 ml-4">
							Detailed descriptions and influences:
							<a class="text-yellow text-link" href="http://www.arisa.se/compendium/node104.html">
								ARiSA - Afferent Coupling</a>,
							<a class="text-yellow text-link"
							   href="https://kariera.future-processing.pl/blog/object-oriented-metrics-by-robert-martin/">
								Artur Ogonowski - Object-oriented metrics by Robert Martin</a>.
						</p>
						<p class="text-justify text-white mb-1 ml-4">
							<span class="text-bold">Efferent Coupling</span><span>, </span>
							On the contrary, if a class in a package depends on a class outside the
							package (outgoing dependencies), it belongs to Efferent Coupling.
						</p>
						<p class="text-white text-justify mb-3 ml-4">
							Detailed descriptions and influences:
							<a class="text-yellow text-link" href="http://www.arisa.se/compendium/node108.html">
								ARiSA - Efferent Coupling</a>,
							<a class="text-yellow text-link"
							   href="https://kariera.future-processing.pl/blog/object-oriented-metrics-by-robert-martin/">
								Artur Ogonowski - Object-oriented metrics by Robert Martin</a>.
						</p>
						<div class="collapse" id="collapse_description">
							<p class="text-justify text-white mb-1 ml-4">
								<span class="text-bold">Instability</span><span>, </span>
								which is measuring whether a package is stable or not. It is the ratio
								of Afferent Coupling to the sum of Afferent Coupling and Efferent Coupling.
								In good practices, the value of instability of component should decrease follow
								the direction of dependency graph. In other word, a component should
								always depends on more stable components.
							</p>
							<p class="text-white text-justify mb-3 ml-4">
								Detailed descriptions and influences:
								<a class="text-yellow text-link" href="http://www.arisa.se/compendium/node111.html">
									ARiSA - Instability</a>,
								<a class="text-yellow text-link"
								   href="https://kariera.future-processing.pl/blog/object-oriented-metrics-by-robert-martin/">
									Artur Ogonowski - Object-oriented metrics by Robert Martin</a>.
							</p>
							<p class="text-justify text-white mb-3 ml-4">
								<span class="text-bold">Abstractness</span><span>, </span>
								This metric calculates the proportion of abstract
								components (i.e. abstract classes and interfaces type) in a package in all components
								(types) in the package, which describing the abstractness of a package. This metric is usually used
								with Instability to indicate whether the package is
								desirable or not.
							</p>
							<p class="text-justify text-white mb-3 ml-4">
								<span class="text-bold">Distance from Main Sequence</span><span>, </span>
								For a desirable package, it could have maximum abstractness with zero instability, and
								vice versa. Moreover, it could also reasonable to achieve balance concerning its
								Abstractness and Instability. Martin (1994) introduced a line, the Main Sequence, to
								represent this set of desirable value pairs. The Distance from the Main Sequence is
								measuring in what distance a package is from this ideal. The metric
								ranges between [0,1].
							</p>
							<p class="text-justify text-white mb-1 ml-4">
								<span class="text-bold">Coupling Between Objects</span><span>, </span>
								The coupling between object classes
								indicates the number of other classes to which it is coupled. In other word, it happens
								when a method declared in one class invokes a method or instance variable defined in
								another class. In practice, the coupling will occur in the following situations: method
								invocations, method references, field accesses, extends, implementations, method
								parameters, return types and exceptions.
							</p>
							<p class="text-white text-justify mb-3 ml-4">
								Detailed descriptions and influences:
								<a class="text-yellow text-link"
								   href="https://maisqual.squoring.com/wiki/index.php/Coupling_Between_Objects">
									Maisqual - Coupling Between Objects</a>,
								<a class="text-yellow text-link" href="http://www.arisa.se/compendium/node105.html">
									ARiSA - Coupling Between Objects</a>.
							</p>
							<p class="text-justify text-white mb-1 ml-4">
								<span class="text-bold">Message Passing Coupling</span><span>, </span>
								A message is passing among the objects of the classes when the object invokes a method
								of another object. In practice, this metric counts the number of
								method invocations from a class to other classes.
							</p>
							<p class="text-white text-justify mb-3 ml-4">
								Detailed descriptions and influences:
								<a class="text-yellow text-link" href="http://www.arisa.se/compendium/node113.html">
									ARiSA - Message Passing Coupling</a>.
							</p>
						</div>
						<a class="text-white text-link" data-toggle="collapse" href="#collapse_description"
						   role="button" aria-expanded="false" aria-controls="collapse_description">
							<i class="fas fa-sort"></i> Expand / Collapse
						</a>
					</div>
				</div>
			</div>
		</div>
	</div>
	
	<!-- Page content -->
	<div class="container-fluid mt--6" th:with="currentProjectInfo = ${projectList.get(projectList.size()-1)}">
		<!--图表-->
		<div class="row">
			<!--chart -->
			<div class="col-xl-12">
				<div class="card">
					<div class="card-header bg-transparent">
						<div class="row align-items-center">
							<div class="col">
								<h6 class="text-muted text-uppercase ls-1 mb-1">Overview</h6>
								<h5 class="h3 mb-0" id="timeline_chart_title">
									{{ title }}
								</h5>
							</div>
							<div class="col">
								<ul class="nav nav-pills justify-content-end">
									<li class="nav-item mr-2 mr-md-0">
										<a href="javascript:void(0);" class="nav-link py-2 px-3 active"
										   data-toggle="tab"
										   onclick="showTimelineChartForPackage()">
											<span class="d-none d-md-block">I/A Graph</span>
											<span class="d-md-none">I/A</span>
										</a>
									</li>
									<li class="nav-item">
										<a id='sloc_timeline_chart' href="javascript:void(0);" class="nav-link py-2 px-3"
										   data-toggle="tab" onclick="showTimelineChartForClass()">
											<span class="d-none d-md-block">CBO & MPC</span>
											<span class="d-md-none">C&M</span>
										</a>
									</li>
								</ul>
							</div>
						</div>
					</div>
					<div id="chart" class="card-body pb-4 px-4 pt-0 col-12" style="height:500px;"></div>
					<div class="modal fade" id="chart_data_model" tabindex="-1" role="dialog"
					     aria-labelledby="row_model_label" aria-hidden="true">
						<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document">
							<div class="modal-content">
								<div class="modal-header">
									<h5 class="modal-title">{{title}}</h5>
									<button type="button" class="close" data-dismiss="modal" aria-label="Close">
										<span aria-hidden="true">&times;</span>
									</button>
								</div>
								<div class="modal-body pt-0">
									<hr class="my-3">
									<div v-for="pointValue in pointValueList">
										<span>{{pointValue}}</span><br>
									</div>
									<hr class="my-3">
									<div v-for="pointDescription in pointDescriptionList">
										<div v-html="pointDescription"></div>
										<hr class="my-1">
									</div>
								</div>
								<div class="modal-footer">
									<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
								</div>
							</div>
						</div>
					</div>
					
					<script type="text/javascript" th:inline="javascript">
              let timeRecords = /*[[${timeRecords}]]*/;
              let packageInstabilityAbstractnessGraphDataset = /*[[${packageInstabilityAbstractnessGraphDataset}]]*/;
              let classCouplingBetweenObjectsDataset = /*[[${classCouplingBetweenObjectsDataset}]]*/;
              let classMessagePassingCouplingDataset = /*[[${classMessagePassingCouplingDataset}]]*/;
              let currentChartLevel = 'package';

              let vm_for_timeline_chart_title = new Vue({
                  el: '#timeline_chart_title',
                  data: {
                      title: "Instability/Abstractness graph."
                  }
              })
              function showTimelineChartForPackage() {
                  vm_for_timeline_chart_title.title = "Instability/Abstractness graph."
                  currentChartLevel = 'package';
                  document.getElementById("chart").style.height = "500px";
                  let chartHeight = document.getElementById("chart").offsetHeight;
                  let chartWidth = document.getElementById("chart").offsetWidth;
                  let squareLength = chartHeight > chartWidth ? chartWidth : chartHeight;
                  squareLength -= 180;
                  let option = {
                      options: initOptions(),
                      baseOption: {
                          legend: {},
                          grid: {bottom: 90, height: squareLength, width: squareLength, top: 'middle', left: 'center'},
                          xAxis: {name: 'Instability', max: 1, interval: 1},
                          yAxis: {name: 'Abstractness', max: 1, interval: 1},
                          timeline: {
                              axisType: 'category', loop: true, autoPlay: false, currentIndex: timeRecords.length - 1,
                              playInterval: 1000, symbol: 'circle', data: timeRecords, animation: false,
                              controlStyle: {showNextBtn: true, showPrevBtn: true, showPlayBtn: true},
                              checkpointStyle: {animation: false},
                              label: {
                                  formatter: function (value, index) {
                                      return value.split(" ")[0];
                                  }
                              }
                          },
                          tooltip: {
                              padding: 10, borderWidth: 1,
                              show: true, enterable: true, trigger: 'item', confine: true,
                              formatter: function (params) {
                                  if (params.componentType === "timeline") {
                                      return params.name;
                                  } else if (params.componentType === "series") {
                                      let value = params.data
                                      let yLabelName = params.seriesName;
                                      return '<div style="border-bottom: 1px solid rgba(255,255,255,.3) ;padding-bottom: 7px;margin-bottom: 7px">'
                                          + 'Package: ' + value[3] + '<br>'
                                          + '<span style="font: 12px">'
                                          + 'Of module: ' + value[4] + '</span>' + '<br>'
                                          + '</div>'
                                          + '<div style="border-bottom: 1px solid rgba(255,255,255,.3) ;padding-bottom: 7px;margin-bottom: 7px">'
                                          + 'Instability : ' + value[0] + '<br>'
                                          + 'Abstractness: ' + value[1] + '<br>'
                                          + 'Distance from Main Sequence: ' + value[2] + '<br>'
                                          + '</div>'
                                          + 'Click the point to see all overlapped data.';
                                  }
                              }
                          },
                      },
                  };
                  timelineChart.clear();
                  timelineChart.resize();
                  timelineChart.setOption(option);
              }

              function initOptions() {
                  let options = [];
                  for (let i = 0; i < timeRecords.length; i++) {
                      options[i] = {
                          series: [
                              {
                                  name: 'Package (Instability, Abstractness)',
                                  type: 'scatter', animation: false,
                                  data: packageInstabilityAbstractnessGraphDataset[timeRecords[i]],
                                  emphasis: {
                                      label: {
                                          show: true, color: '#000000', position: 'top', fontWeight: 'normal',
                                          formatter: function (params) {
                                              return params.data[3];
                                          },
                                      },
                                  },
                                  markLine: {
                                      animation: false, silent: true,
                                      label: {position: 'middle', color: '#000'},
                                      // tooltip: {formatter: 'The Main Sequence'},
                                      lineStyle: {type: 'dotted', color: '#000',},
                                      data: [
                                          [{
                                              name: 'The Main Sequence',
                                              coord: [0, 1], symbol: 'none'
                                          }, {
                                              coord: [1, 0], symbol: 'none'
                                          }], [{
                                              name: 'Inflexibility',
                                              label: {
                                                  position: 'insideMiddleBottom', color: '#000'
                                              },
                                              coord: [0, 0.5], symbol: 'none'
                                          }, {
                                              coord: [0.5, 0], symbol: 'none'
                                          }], [{
                                              name: 'Uselessness',
                                              coord: [1, 0.5], symbol: 'none'
                                          }, {
                                              coord: [0.5, 1], symbol: 'none'
                                          }],
                                      ],
                                  },
                              },
                          ]
                      }
                  }
                  return options;
              }

              function showTimelineChartForClass() {
                  vm_for_timeline_chart_title.title =
		                  "The trends of the Coupling Between Objects and Message Passing Coupling for all classes."
                  currentChartLevel = 'class';
                  let option = {
                      legend: {},
                      grid: {bottom: 90},
                      xAxis: {
                          name: "Time", type: 'category', nameLocation: 'middle',
                          splitLine: {show: true, lineStyle: {type: 'solid'}},
                          splitArea: {interval: 0,},
                          axisLabel: {
                              formatter: function (value, index) {
                                  return value.split(" ")[0];
                              }
                          }
                      },
                      yAxis: [{
                          name: "Coupling Between Objects", type: 'value', nameLocation: 'center',
                          nameRotate: 90, nameGap: 30
                      }, {
                          name: "Message Passing Coupling", type: 'value', nameLocation: 'center',
                          nameRotate: 270, nameGap: 30
                      }],
                      series: [{
                          name: 'Classes regarding the Coupling Between Objects', type: 'scatter', yAxisIndex: 0,
                          data: classCouplingBetweenObjectsDataset, symbolOffset: [-10, 0],
                          emphasis: {
                              label: {
                                  show: true, color: '#000000', position: 'top', fontWeight: 'normal',
                                  formatter: function (params) {
                                      return params.data[2];
                                  },
                              },
                          },
                      }, {
                          name: 'Classes regarding the Message Passing Coupling', type: 'scatter', yAxisIndex: 1,
                          data: classMessagePassingCouplingDataset, symbolOffset: [10, 0],
                          emphasis: {
                              label: {
                                  show: true, color: '#000000', position: 'top', fontWeight: 'normal',
                                  formatter: function (params) {
                                      return params.data[2];
                                  },
                              },
                          },
                      }],
                      dataZoom: [
                          {type: 'slider', xAxisIndex: 0, start: 0, end: 100},
                          {type: 'inside', xAxisIndex: 0, start: 0, end: 100},
                          {type: 'slider', yAxisIndex: 0, left: 20, start: 0, end: 100},
                          {type: 'slider', yAxisIndex: 1, right: 20, start: 0, end: 100},
                      ],
                      tooltip: {
                          padding: 10, borderWidth: 1,
                          show: true, enterable: true, trigger: 'item', confine: true,
                          formatter: function (params) {
                              let value = params.data
                              return '<div style="border-bottom: 1px solid rgba(255,255,255,.3) ;padding-bottom: 7px;margin-bottom: 7px">'
                                  + 'Class: ' + value[2] + '<br>' + 'of Module: ' + value[3] + '<br>'
                                  + params.seriesName.replace("Classes regarding the ", "") + ": " + value[1]
                                  + '</div>'
                                  + 'Click the point to see all overlapped data.';
                          }
                      },
                  };
                  document.getElementById("chart").style.height = "550px";
                  timelineChart.clear();
                  timelineChart.resize();
                  timelineChart.setOption(option);
              }

              // 基于准备好的dom，初始化echarts实例
              let timelineChart = echarts.init(document.getElementById('chart'));

              // 用于显示timeline chart的重叠数据
              let chart_data_vm = new Vue({
                  el: '#chart_data_model',
                  data: {
                      title: '',
                      pointValueList: [],
                      pointDescriptionList: [],
                  }
              })
              let currentTimelineIndex = timeRecords.length - 1;
              timelineChart.on('timelinechanged', function (params) {
                  currentTimelineIndex = params.currentIndex
              });
              timelineChart.on('click', function (param) {
                  if (currentChartLevel === 'package') {
                      chart_data_vm.title = timeRecords[currentTimelineIndex];

                      let pointValueList = [];
                      pointValueList.push("Instability: " + param.value[0]);
                      pointValueList.push("Abstractness: " + param.value[1]);
                      pointValueList.push("Distance from Main Sequence: " + param.value[2]);
                      chart_data_vm.pointValueList = pointValueList;

                      let x = param.value[0];
                      let y = param.value[1];
                      let pointDescriptionList = [];
                      for (let key in packageInstabilityAbstractnessGraphDataset) {
                          if (key === timeRecords[currentTimelineIndex]) {
                              for (let row of packageInstabilityAbstractnessGraphDataset[key]) {
                                  if (row[0] === x && row[1] === y) {
                                      let text = '<span style="font: 12px">'
                                          + 'Package: ' + row[3] + '</span>' + '<br>'
                                          + '<span style="font: 12px">'
                                          + 'of Module: ' + row[4] + '</span>' + '<br>';
                                      pointDescriptionList.push(text);
                                  }
                              }
                          }
                      }
                      chart_data_vm.pointDescriptionList = pointDescriptionList;
                  } else {
                      chart_data_vm.title = param.value[0];

                      let pointValueList = [];
                      pointValueList.push(param.seriesName + ": " + param.value[1]);
                      chart_data_vm.pointValueList = pointValueList;

                      let targetDataset;
                      if (param.seriesName === "Coupling Between Objects") {
                          targetDataset = classCouplingBetweenObjectsDataset;
                      } else {
                          targetDataset = classMessagePassingCouplingDataset;
                      }
                      let x = param.value[0];
                      let y = param.value[1];
                      let pointDescriptionList = [];
                      targetDataset.forEach(row => {
                          if (row[0] === x && row[1] === y) {
                              let text = '<span style="font: 12px">'
                                  + 'Class: ' + row[2] + '</span>' + '<br>'
                                  + '<span style="font: 12px">'
                                  + 'Of module: ' + row[3] + '</span>' + '<br>';
                              pointDescriptionList.push(text);
                          }
                      });
                      chart_data_vm.pointDescriptionList = pointDescriptionList;
                  }

                  $('#chart_data_model').modal('show');
              });
					
					
					</script>
				
				</div>
			</div>
		</div>
		<!--表格-->
		<div class="row">
			<!-- 选择记录时间 -->
			<div class="col-xl-12">
				<div class="card-header border-0">
					<div class="row align-items-center">
						<div class="col-auto">
							<h6 class="text-uppercase text-muted ls-1 mb0">Details</h6>
							
							<!-- dropdown -->
							<div class="nav-item dropdown">
								<a class="nav-link pr-0" href="#" role="button" data-toggle="dropdown" aria-haspopup="true"
								   aria-expanded="false">
											<span class="h3 mb-0 mr-2" id="current_record_time"
											      th:text="${#dates.format(currentProjectInfo.getCreateDate(), 'yyyy-MM-dd HH:mm:ss')}"></span>
									<i class="fas fa-caret-down"></i>
								</a>
								<div class="dropdown-menu">
									<a th:class="${timeRecordStat.index} eq ${timeRecords.size()-1} ? 'dropdown-item active' : 'dropdown-item'"
									   href="javascript:void(0);"
									   th:each="timeRecord,timeRecordStat : ${timeRecords}"
									   th:onclick="selectRecordTime(this,[[${timeRecordStat.index}]])">
										<span th:text="${timeRecord}"></span>
									</a>
								</div>
							</div>
						
						</div>
					
					</div>
				</div>
			</div>
			<!--表格-->
			<div class="col-xl-12">
				<div class="card table-outline">
					<div class="table-responsive">
						<div id="toolbar">
							<div class="form-inline" role="form">
								<a id="previous-btn" class="btn btn-outline-primary btn-sm invisible"
								   href="javascript:void(0);"
								   onclick="showPackageCoupling()">
									< previous</a>
							</div>
						</div>
						<table id="table"></table>
					</div>
				</div>
			</div>
			<!-- Modal -->
			<div class="modal fade" id="row_model" tabindex="-1" role="dialog"
			     aria-labelledby="row_model_label" aria-hidden="true">
				<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
					<div class="modal-content">
						<div class="modal-header">
							<h5 class="modal-title" id="row_model_label">
								<span class="h3 text-uppercase text-muted mr-2">{{ recordType }}</span>
								<span class="h3">{{ recordName }}</span>
							</h5>
							<button type="button" class="close" data-dismiss="modal" aria-label="Close">
								<span aria-hidden="true">&times;</span>
							</button>
						</div>
						<div class="modal-body">
							<div id="complexity_row_chart" class="card-body pb-4 px-4 pt-0 col-12" style="height:450px;"></div>
						</div>
						<div class="modal-footer">
							<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
						</div>
					</div>
				</div>
			
			</div>
		
		</div>
		<!--common modals-->
		<modal th:replace="fragments/common :: modals"></modal>
		<!-- Footer -->
		<footer th:replace="fragments/common :: footer"></footer>
	</div>
</div>
<script th:replace="fragments/common :: footer_imports"></script>
<script>
    $(function () {
        // 首次渲染图表
        showTimelineChartForPackage();
        // 首次渲染表格
        showPackageCoupling();
    })

    let $table = $('#table')
    let projectRecordIndex = -1;
    let currentPackageQualifiedName = "";
    let isCurrentLevelClass = false;


    // 选择记录
    function selectRecordTime(obj, index) {
        projectRecordIndex = index;
        let newTime = $(obj).text()
        $('#current_record_time').text(newTime)
        $(obj).siblings().removeClass("active")
        $(obj).addClass("active");
        if (isCurrentLevelClass) {
            showClassCoupling(currentPackageQualifiedName);
        } else {
            showPackageCoupling();
        }
    }

    // 表格：包级别的度量数据
    function showPackageCoupling() {
        isCurrentLevelClass = false;
        let columns = [{
            field: 'chart', title: ''
        }, {
            field: 'name', title: 'Package Name', sortable: true,
            formatter: function (value, row) {
                return '<a href="javascript:void(0);" ' +
                    'onclick="showClassCoupling(\'' + row.name + '\')">' +
                    value + '</a>';
            },
        }, {
            field: 'afferentCoupling', title: 'Afferent Coupling', sortable: true
        }, {
            field: 'efferentCoupling', title: 'Efferent Coupling', sortable: true
        }, {
            field: 'instability', title: 'Instability', sortable: true
        }, {
            field: 'abstractness', title: 'Abstractness', sortable: true
        }, {
            field: 'distance', title: 'Distance from Main Sequence', sortable: true
        }, {
            field: 'module', title: 'of Which Module', sortable: true
        }];
        $.get("/dashboard/coupling/table/package?projectRecordIndex=" + projectRecordIndex).done(function (data) {
            let dataset = data;
            //给每行前面加上趋势图按钮（弹出模态框）
            for (i = 0; i < dataset.length; i++) {
                dataset[i].chart =
                    '<a class="table-chart-icon" href="javascript:void(0);" data-toggle="modal" '
                    + 'data-target="#row_model" onclick="showTableChartForPackage(\'' +
                    dataset[i].name + '\')">'
                    + '<i class="fas fa-chart-bar"></i></a>'
            }
            buildTable($table, dataset, columns, 2, 0)
            $("#previous-btn").addClass("invisible");
        });
    }

    //表格：类级别的度量数据
    function showClassCoupling(qualifiedName) {
        currentPackageQualifiedName = qualifiedName;
        isCurrentLevelClass = true;
        let columns = [{
            field: 'chart', title: ''
        }, {
            field: 'name', title: 'Class Name', sortable: true
        }, {
            field: 'couplingBetweenObjects', title: 'Coupling Between Objects', sortable: true
        }, {
            field: 'afferentCoupling', title: 'Afferent Coupling', sortable: true
        }, {
            field: 'efferentCoupling', title: 'Efferent Coupling', sortable: true
        }, {
            field: 'instability', title: 'Instability', sortable: true
        }, {
            field: 'messagePassingCoupling', title: 'Message Passing Coupling', sortable: true
        }, {
            field: 'type', title: 'Class Type', sortable: true
        }, {
            field: 'declaration', title: 'Class Location', sortable: true
        }, {
            field: 'package', title: 'of Which Package', sortable: true
        }, {
            field: 'module', title: 'of Which Module', sortable: true
        }];
        $.get("/dashboard/coupling/table/class?pkgQualifiedName=" + qualifiedName +
            "&projectRecordIndex=" + projectRecordIndex).done(function (data) {
            let dataset = data;
            //给每行前面加上趋势图按钮（弹出模态框）
            for (i = 0; i < dataset.length; i++) {
                dataset[i].chart =
                    '<a class="table-chart-icon" href="javascript:void(0);" data-toggle="modal" '
                    + 'data-target="#row_model" onclick="showTableChartForClass(\'' +
                    dataset[i].qualifiedName + '\')">'
                    + '<i class="fas fa-chart-bar"></i></a>'
            }
            buildTable($table, dataset, columns, 2, 0)
            $("#previous-btn").removeClass("invisible");
        });
    }

    // 重新渲染表格
    function buildTable($el, dataset, columns, fixedNumber, fixedRightNumber) {
        $el.bootstrapTable('destroy').bootstrapTable({
            height: 500,
            columns: columns,
            data: dataset,
            toolbar: '#toolbar',
            search: true,
            showColumns: true,
            fixedColumns: true,
            fixedNumber: fixedNumber,
            fixedRightNumber: fixedRightNumber,
            // buttons: "",
            // buttonsPrefix: "",
            // buttonsClass: "btn btn-sm btn-outline-primary",
            showColumnsToggleAll: true,
            detailViewByClick: true,
            iconSize: "sm",
            showFullscreen: true,
        })
    }

    // 用于修改模块框title
    let coupling_table_chart_title_vm = new Vue({
        el: '#row_model_label',
        data: {
            recordType: '',
            recordName: '',
        }
    })

    // 指定图表的配置项和数据
    let tableChartOptForClass = {
        grid: {
            bottom: '100'
        },
        // 声明一个 X 轴，类目轴（category）。默认情况下，类目轴对应到 dataset 第一列。
        xAxis: {
            type: 'category'
        },
        yAxis: [
            {
                name: "Actual values",
                type: 'value',
                nameLocation: 'center',
                nameRotate: 90,
                nameGap: 40,
                interval: 1,
            }, {
                name: "Relative values",
                type: 'value',
                nameLocation: 'center',
                nameRotate: 270,
                nameGap: 40,
            }
        ],
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                snap: true,
                type: "line",
            }
        },
        dataZoom: [
            {
                type: 'slider',
                xAxisIndex: 0,
                start: 0,
                end: 100
            },
            {
                type: 'inside',
                xAxisIndex: 0,
                start: 0,
                end: 100
            },
            {
                type: 'slider',
                yAxisIndex: 0,
                left: 20,
                start: 0,
                end: 100
            },
            {
                type: 'slider',
                yAxisIndex: 1,
                right: 20,
                start: 0,
                end: 100
            }
        ],
    };
    let complexityTableChart = echarts.init(document.getElementById('complexity_row_chart'));


    function showTableChartForPackage(qualifiedName) {
        coupling_table_chart_title_vm.recordName = qualifiedName;
        coupling_table_chart_title_vm.recordType = "Package";
        // 异步加载数据
        complexityTableChart.clear();
        complexityTableChart.setOption(tableChartOptForClass);
        $.get("/dashboard/coupling/table/chart/package?qualifiedName=" + qualifiedName).done(function (data) {
            // 填入数据
            console.log(data)
            complexityTableChart.setOption({
                legend: {
                    data: ["Afferent Coupling", "Efferent Coupling", "Instability",
                        "Abstractness", "Distance from Main Sequence"]
                },
                dataset: {
                    // 提供一份数据。
                    source: data
                },
                series: [
                    {
                        type: 'line', name: 'Afferent Coupling', yAxisIndex: 0,
                        lineStyle: {width: 3}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Efferent Coupling', yAxisIndex: 0,
                        lineStyle: {width: 3}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Instability', yAxisIndex: 1,
                        lineStyle: {width: 3, type: "dashed"}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Abstractness', yAxisIndex: 1,
                        lineStyle: {width: 3, type: "dashed"}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Distance from Main Sequence', yAxisIndex: 1,
                        lineStyle: {width: 3, type: "dashed"}, emphasis: {label: {show: true}},
                    },
                ],
            });
        });
    }

    function showTableChartForClass(qualifiedName) {
        coupling_table_chart_title_vm.recordName = qualifiedName;
        coupling_table_chart_title_vm.recordType = "Class";
        // 异步加载数据
        complexityTableChart.clear();
        complexityTableChart.setOption(tableChartOptForClass);
        $.get("/dashboard/coupling/table/chart/class?qualifiedName=" + qualifiedName).done(function (data) {
            // 填入数据
            complexityTableChart.setOption({
                legend: {
                    data: ["Message Passing Coupling", "Coupling Between Objects", "Afferent Coupling",
                        "Efferent Coupling", "Instability"]
                },
                dataset: {
                    // 提供一份数据。
                    source: data
                },
                series: [
                    {
                        type: 'line', name: 'Message Passing Coupling', yAxisIndex: 0,
                        lineStyle: {width: 3,}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Coupling Between Objects', yAxisIndex: 0,
                        lineStyle: {width: 3,}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Indegree', yAxisIndex: 0,
                        lineStyle: {width: 3,}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Outdegree', yAxisIndex: 0,
                        lineStyle: {width: 3,}, emphasis: {label: {show: true}},
                    },
                    {
                        type: 'line', name: 'Instability', yAxisIndex: 1,
                        lineStyle: {width: 3, type: "dashed"}, emphasis: {label: {show: true}},
                    },
                ],
            });
        });
    }

    // 让echarts在模态框打开后重新渲染
    $('#row_model').on('shown.bs.modal', function () {
        complexityTableChart.resize()
    })


</script>

</body>

</html>
